package cn.echogo.framework.core;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;

import cn.echogo.framework.http.EGHttpClientException;
import cn.echogo.framework.http.imp.EGHttpRequestRetryHandler;

import com.google.gson.Gson;

public class HttpInvokerImp implements HttpInvoker {

	private static final int DEFAULT_TIMEOUT_CONNECTION = 30 * 1000; // 默认连接超时时间（单位：毫秒）
	private static final int DEFAULT_TIMEOUT_SOCKET = 30 * 1000; // 默认Socket超时时间（单位：毫秒）
	private static final int DEFAULT_BUFFER_SIZE = 8192 * 20;
	private static final String USER_AGENT = "Mozil1a/4.0 (compatible; MS1E 7.0; Windows NT 6.1; WOW64; )";
	private static final String DEFAULT_CHARSET = "UTF-8"; // 默认编码格式
	private static final String CONTENT_TYPE = "application/x-www-form-urlencoded";

	private DefaultHttpClient httpclient = null;
	
	private Cookie[] cookies;
	
	public HttpInvokerImp(Cookie[] cookies) {
		this.cookies = cookies;
	}
	
	public HttpInvokerImp() {
	}

	private synchronized DefaultHttpClient getHttpClient() {
		if (httpclient != null) {
			return httpclient;
		}

		int timeoutConnection = DEFAULT_TIMEOUT_CONNECTION;
		int timeoutSocket = DEFAULT_TIMEOUT_SOCKET;
		int bufferSize = DEFAULT_BUFFER_SIZE;

		HttpParams httpParameters = new BasicHttpParams();

		ConnManagerParams.setMaxTotalConnections(httpParameters, 10);
		ConnManagerParams.setMaxConnectionsPerRoute(httpParameters, new ConnPerRouteBean(8));

		HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
		HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
		HttpConnectionParams.setSocketBufferSize(httpParameters, bufferSize);

		SchemeRegistry schemeRegistry = new SchemeRegistry();
		schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
		schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
		ThreadSafeClientConnManager mgr = new ThreadSafeClientConnManager(httpParameters, schemeRegistry); // 线程安全

		HttpClientParams.setRedirecting(httpParameters, true);
		HttpClientParams.setCookiePolicy(httpParameters, CookiePolicy.BROWSER_COMPATIBILITY);
		HttpProtocolParams.setUserAgent(httpParameters, USER_AGENT);

		httpclient = new DefaultHttpClient(mgr, httpParameters);
		
		//Session设置
		if(cookies != null && cookies.length > 0) {
			BasicCookieStore cookieStore = new BasicCookieStore();
			cookieStore.addCookies(cookies);
			httpclient.setCookieStore(cookieStore);
		}

		// 自动重连策略
		httpclient.setHttpRequestRetryHandler(new EGHttpRequestRetryHandler());

		return httpclient;
	}

	@Override
	public String execute(String url, Object content, int method) throws EGHttpClientException {
		HttpRequestBase request;
		HttpResponse response;
		switch (method) {
		case GET:
			HttpGet httpGet = new HttpGet(url);
			request = httpGet;
			break;
		case POST:
			HttpPost httpPost = new HttpPost(url);
			httpPost.addHeader("content-type", CONTENT_TYPE);
			HttpEntity reqEntity = null;
			try {
				reqEntity = new StringEntity((String) content, DEFAULT_CHARSET);
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			httpPost.setEntity(reqEntity);
			request = httpPost;
			break;
		default:
			throw new IllegalArgumentException("httpMethod参数不支持的值：" + method);
		}

		HttpClient httpClient = getHttpClient();
		try {
			HttpResponse httpRsp = httpClient.execute(request);
			if (httpRsp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
				throw new EGHttpClientException();
			}
			HttpEntity rspEntity = httpRsp.getEntity();
			String responseContent = EntityUtils.toString(rspEntity, DEFAULT_CHARSET);
			rspEntity.consumeContent();
			return responseContent;
		} catch (ClientProtocolException e) {
			throw new EGHttpClientException();
		} catch (IOException e) {
			throw new EGHttpClientException();
		} finally {
			request.abort();
		}
	}

	@Override
	public <T> T get(String url, Type responseType) throws EGHttpClientException {
		String responseContent = execute(url, null, GET);
		Gson gson = new Gson();
		T result = gson.fromJson(responseContent, responseType);
		return result;
	}

	@Override
	public <T> T post(String url, Object content, Type responseType) throws EGHttpClientException {
		String responseContent = execute(url, content, POST);
		Gson gson = new Gson();
		T result = gson.fromJson(responseContent, responseType);
		return result;
	}

}
